package com.smart.stock.common.util.stock;

import com.smart.stock.common.util.h2.H2ConnectionPool;
import com.smart.stock.common.util.h2.H2Util;
import com.smart.stock.common.util.spring.EntityUtil;
import com.smart.stock.module.GlobalEnums;
import com.smart.stock.module.maindata.entity.Stock;
import com.smart.stock.module.maindata.entity.StockCodeInfo;
import com.smart.stock.module.maindata.entity.StockPriceDaily;
import com.smart.stock.module.spider.util.TradingDateUtil;
import com.smart.stock.common.util.db.DBUtil;
import com.smart.stock.module.GlobalConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Component
public class StockUtil {

    public static String yIfTrue(boolean bool)  {
        if (bool) {
            return "Y";
        }

        return "N";
    }
    /**
     * 获取股票基本信息
     * @param template
     * @param code
     * @return
     */
    public static ArrayList<String> getStockInfoByCode(MongoTemplate template, String code) throws Exception{
        Connection conn = H2ConnectionPool.getConnection();
        Statement stmt = conn.createStatement();
        H2Util<StockCodeInfo> h2Util = new H2Util<>();
        String entityName = EntityUtil.getEntityNameByCode(StockCodeInfo.class,null);
        if (!H2Util.tableExist(entityName)){
            entityName = h2Util.createH2TableFromMongo(template,StockCodeInfo.class,null);

        }
        ResultSet rs = stmt.executeQuery("SELECT * FROM "+entityName+" WHERE code = '"+code+"'");
        ArrayList<String> list = new ArrayList<>();
        while (rs.next()) {
            list.add(rs.getString("name"));
            list.add(rs.getString("type"));
            list.add(rs.getString("area"));
            list.add(rs.getString("industry"));
        }
        H2ConnectionPool.returnConnection(conn);
        return list;
    }

    /**
     * 获取股票基本信息
     * @param template
     * @param code
     * @return
     * @throws Exception
     */
    public static List<StockPriceDaily> getStockPriceDailyByCode(MongoTemplate template, String code){
        List<StockPriceDaily> list = template.find(new Query(Criteria.where("code").is(code)).with(Sort.by(Sort.Direction.ASC,"tradeDate")), StockPriceDaily.class);
        return list;
    }


    public static String getIndexesNameByCode(String code){
        if (code.equals(GlobalConstant.INDEX_SH)) return GlobalConstant.INDEX_SH_NAME;
        if (code.equals(GlobalConstant.INDEX_SZ)) return GlobalConstant.INDEX_SZ_NAME;
        if (code.equals(GlobalConstant.INDEX_CYB)) return GlobalConstant.INDEX_CYB_NAME;
        if (code.equals(GlobalConstant.INDEX_KCB)) return GlobalConstant.INDEX_KCB_NAME;
        return "";
    }

    public static List getStockVolIncrease(MongoTemplate template, String code) throws Exception {
        List<StockPriceDaily> list = H2Util.createListFromMongoByCode(template, StockPriceDaily.class,code);
        List stockVolIncrease = getStockVolIncrease(list);
        return stockVolIncrease;
    }

    /**
     * 成交量放大倍数，放量
     * @param list
     * @return
     * @throws Exception
     */
    public static List getStockVolIncrease(List<StockPriceDaily> list) {
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);
            if (i==0) {
                currentStock.setVolIncrease(0d);
            } else {
                StockPriceDaily lastStock = list.get(i-1);
                currentStock.setVolIncrease(currentStock.getVol()/lastStock.getVol());
            }
            list.set(i, currentStock);
        }
        return list;
    }

    /**
     * 历史新高
     */
    public static List getStockNewHight(List<StockPriceDaily> list) {
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);

            //计算新高
            String isNewHigh = "Y";
            if (i == 0) {
                currentStock.setIsNewHigh("N");
            } else {
                for (int i1 = 0; i1 < i; i1++) {
                    StockPriceDaily stocki1 = list.get(i1);
                    if (stocki1.getClose()>currentStock.getClose()) {
                        isNewHigh = "N";
                        break;
                    }
                }

            }
            currentStock.setIsNewHigh(isNewHigh);


            //计算新低
            String isNewLow = "Y";
            if (i == 0) {
                currentStock.setIsNewLow("N");
            } else {
                for (int i1 = 0; i1 < i; i1++) {
                    StockPriceDaily stocki1 = list.get(i1);
                    if (stocki1.getClose()<currentStock.getClose()) {
                        isNewLow = "N";
                        break;
                    }
                }

            }
            currentStock.setIsNewLow(isNewLow);

            //把当前设置了新高新低的股票记录设置回原来的list中
            list.set(i, currentStock);
        }
        return list;
    }
    /**
     * 盈亏比
     */
    public static List getStockProfitLoss(List<StockPriceDaily> list) throws Exception {
        List<Double> maybeProfitLoss = getMaybeProfitLoss(list);
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);
            currentStock.setMaybeProfit(maybeProfitLoss.get(1));
            currentStock.setMaybeLoss(maybeProfitLoss.get(2));
            currentStock.setMaybeProfitLoss(maybeProfitLoss.get(0));
            //把当前设置了新高新低的股票记录设置回原来的list中
            list.set(i, currentStock);
        }
        return list;
    }
    /**
     * 锤子线
     */
    public static List getStockShapes(List<StockPriceDaily> list)  {
        for (int i = 0; i < list.size(); i++) {

            StockPriceDaily currentStock = list.get(i);
            boolean shapeOfHammer = getShapeOfHammer(currentStock);
            boolean shapeOfHangOneself = getShapeOfHangOneself(currentStock);
            currentStock.setIsShapeOfHammer(yIfTrue(shapeOfHammer));
            currentStock.setIsShapeOfHangOneself(yIfTrue(shapeOfHangOneself));

            if (i == 0) {

            } else {
                StockPriceDaily lastStock = list.get(i-1);
                boolean shapeOfSwallowUp = getShapeOfSwallowUp(lastStock,currentStock);
                boolean shapeOfSwallowDown = getShapeOfSwallowDown(lastStock,currentStock);
                boolean shapeOfStabUp = getShapeOfStabUp(lastStock,currentStock);
                boolean shapeOfStabDown = getShapeOfStabDown(lastStock,currentStock);
                currentStock.setIsShapeOfSwallowUp(yIfTrue(shapeOfSwallowUp));
                currentStock.setIsShapeOfSwallowDown(yIfTrue(shapeOfSwallowDown));
                currentStock.setIsShapeOfStabUp(yIfTrue(shapeOfStabUp));
                currentStock.setIsShapeOfStabDown(yIfTrue(shapeOfStabDown));
            }
            //把当前设置了新高新低的股票记录设置回原来的list中
            list.set(i, currentStock);
        }
        return list;
    }

    public static List getStockNewHigh(MongoTemplate template,String code)  {
        List<StockPriceDaily> list = template.find(new Query(Criteria.where("code").is(code)).with(Sort.by(Sort.Direction.ASC, "tradeDate")), StockPriceDaily.class);
        List stockNewHight = getStockNewHight(list);
        return stockNewHight;
    }

    public static String getAllStockNewHigh(MongoTemplate template) throws Exception {
        List<StockCodeInfo> all = template.findAll(StockCodeInfo.class);
        ArrayList<List> arrayList = new ArrayList<>();
        String h2Table = "temp_all_stock_newhign";
        if (!H2Util.tableExist(h2Table)) {
            for (int i = 0; i < all.size(); i++) {
                StockCodeInfo stock = all.get(i);
                String code = stock.getCode();
                List stockNewHigh = getStockNewHigh(template, code);
                arrayList.add(stockNewHigh);

                if (i == 0) {
                    H2Util.createH2TableFromList(stockNewHigh,h2Table);
                } else {
                    if (stockNewHigh.size() == 0) {
                        System.out.println("第"+i+"只股票,"+stock.getCode()+"-"+stock.getName()+",未计算出新高数据================================================");
                        continue;
                    } else {
                        H2Util.insertH2TableFromList(stockNewHigh,h2Table);
                    }
                }

            }
        }


        String sql = "select a.*, a.newHighCnt-a.newLowCnt netCnt   from (\n" +
                "SELECT to_char(tradedate) tradedate,sum(case when isnewhigh = 'Y' then 1 else 0 end) as newHighCnt ,sum(case when isnewlow = 'Y' then 1 else 0 end) as newLowCnt FROM TEMP_ALL_STOCK_NEWHIGN group by tradedate \n" +
                ") as a order by 1";
        log.info(sql);
        ResultSet rs = H2Util.execQuerySQL(sql);
        String json = DBUtil.resultSetToJsonString(rs);
        return json;
    }

    public static List getAllStockUpDown(MongoTemplate template) throws Exception {
        String entityName = EntityUtil.getEntityNameByCode(StockPriceDaily.class,null);
        if (!H2Util.tableExist(entityName)){
            H2Util.createH2TableFromMongo(template, StockPriceDaily.class,null);
        }

        String sql = String.format(
                "select tradeDate,\n" +
                        "sum(case when pctchg > 9.5 then 1 else 0 end) max_price9 ,\n" +
                        "sum(case when pctchg >= 7 and  pctchg <9.5 then 1 else 0 end) max_price79 ,\n" +
                        "sum(case when pctchg >= 5 and  pctchg<7 then 1 else 0 end) max_price57 ,\n" +
                        "sum(case when pctchg >= 3 and  pctchg<5 then 1 else 0 end) max_price35 ,\n" +
                        "sum(case when pctchg >= 1 and  pctchg<3 then 1 else 0 end) max_price13 ,\n" +
                        "sum(case when pctchg >= -1 and  pctchg<1 then 1 else 0 end) max_price11,\n" +
                        "sum(case when pctchg >= -3 and  pctchg<-1 then 1 else 0 end) min_price13 ,\n" +
                        "sum(case when pctchg >= -5 and  pctchg<-3 then 1 else 0 end) min_price35 ,\n" +
                        "sum(case when pctchg >= -7 and  pctchg<-5 then 1 else 0 end) min_price57 ,\n" +
                        "sum(case when pctchg >= -9.5 and  pctchg<-7 then 1 else 0 end) min_price79 ,\n" +
                        "sum(case when pctchg <-9.5 then 1 else 0 end) min_price9 \n" +
                        "from %s group by tradeDate order by 1",entityName);
        System.out.println("大盘涨跌停指数统计sql:"+sql);
        ResultSet rs = H2Util.execQuerySQL(sql);

        ArrayList<Object> list = new ArrayList<>();
        while (rs.next()) {
            ArrayList<Object> arrayList = new ArrayList<>();
            for (int i = 1; i <= 12; i++) {
                if (i == 1) {
                    arrayList.add(String.format("'%s'",rs.getInt(i)));
                } else {
                    arrayList.add(rs.getInt(i));
                }

            }
            list.add(arrayList);
        }
        return list;
    }
        /**
         * 获取股票行情信息
         * @param template
         * @param code
         * @return
         */
    public static List getStockPriceMinMax(MongoTemplate template, String code){
        Connection conn = H2ConnectionPool.getConnection();
        ArrayList list = new ArrayList<>();
        Statement stmt = null;
        String table = EntityUtil.getEntityNameByCode(StockPriceDaily.class,code);
        try {
            stmt = conn.createStatement();
            H2Util<StockPriceDaily> h2Util = new H2Util<>();
            String entityName = EntityUtil.getEntityNameByCode(StockPriceDaily.class,code);
            if (!H2Util.tableExist(entityName)) {
                table = h2Util.createH2TableFromMongo(template, StockPriceDaily.class,code);
            }

            StockPriceDaily maxVo = new StockPriceDaily();
            StockPriceDaily minVo = new StockPriceDaily();
            StockPriceDaily vo2 = new StockPriceDaily();
            StockPriceDaily vo3 = new StockPriceDaily();


            //top1
            String sql = "select * from "+table+" where code = '"+code+"' and close in (SELECT max(close) FROM "+table+" WHERE code = '"+code+"') order by tradeDate desc limit 1";
            System.out.println("sql:"+sql);
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                maxVo.setTradeDate(rs.getInt("tradeDate"));
                maxVo.setClose(rs.getDouble("close"));
                maxVo.setOpen(rs.getDouble("open"));
                list.add(maxVo);
            }

            //如果创新高，最大值在最近3个交易日内，则取最后一个交易日为终点
            String baseDate = TradingDateUtil.minusDateNow(0, 0, 3, "yyyyMMdd");
            if (maxVo.getTradeDate()>=Integer.valueOf(baseDate)) {
                ResultSet rs9 = null;
                String sql9 = "select * from "+table+" where code = '"+code+"' and tradeDate in (SELECT max(tradeDate) FROM "+table+" WHERE code = '"+code+"' ) limit 1";
                System.out.println("sql9:"+sql9);
                rs9 = stmt.executeQuery(sql9);
                StockPriceDaily vo9 = new StockPriceDaily();
                while (rs9.next()) {
                    vo9.setTradeDate(rs9.getInt("tradeDate"));
                    vo9.setClose(rs9.getDouble("close"));
                    vo9.setOpen(rs9.getDouble("open"));
                    list.add(vo9);
                }
            } else {
                //取最低点
                String sqlMin = "select * from "+table+" " +
                        "where code = '"+code+"' " +
                        "and tradeDate > '" + maxVo.getTradeDate() + "' " +
                        "and close in (SELECT min(close) FROM "+table+" " +
                        "WHERE code = '"+code+"' " +
                        "and tradeDate > '" + maxVo.getTradeDate() + "' " +
                        ") " +
                        "order by tradeDate desc " +
                        "limit 1";
                System.out.println("sqlMin:"+sqlMin);
                ResultSet rsMin = stmt.executeQuery(sqlMin);
                while (rsMin.next()) {
                    minVo.setTradeDate(rsMin.getInt("tradeDate"));
                    minVo.setClose(rsMin.getDouble("close"));
                    minVo.setOpen(rsMin.getDouble("open"));
                    list.add(minVo);
                }

                //根据最低点的时间，往前往后推N个天
                String daysAgoMin = TradingDateUtil.minusDate(0, 0, GlobalConstant.DATE_MINUS, minVo.getTradeDate().toString());
                String daysLaterMin = TradingDateUtil.plusDate(0, 0, GlobalConstant.DATE_PLUS, minVo.getTradeDate().toString());
                //todo：处理边界

                //top2
//                String daysLater2 = TradingDateUtil.plusDate(0, 0, GlobalConstant.DATE_PLUS, maxVo.getTradeDate().toString());
                String sql2 = "select * from "+table+" " +
                        "where code = '"+code+"' " +
                        "and tradeDate between '"+daysAgoMin+"' and '"+minVo.getTradeDate()+"'" +
                        "and close in (SELECT max(close) FROM "+table+" " +
                        "WHERE code = '"+code+"' " +
                        "and tradeDate between '"+daysAgoMin+"' and '"+minVo.getTradeDate()+"') " +
                        "order by tradeDate desc limit 1";

                System.out.println("sql2:"+sql2);
                ResultSet rs2 = stmt.executeQuery(sql2);
                while (rs2.next()) {
                    vo2.setTradeDate(rs2.getInt("tradeDate"));
                    vo2.setClose(rs2.getDouble("close"));
                    vo2.setOpen(rs2.getDouble("open"));
                    list.add(vo2);
                }

                //top3
//                String daysLater3 = TradingDateUtil.plusDate(0, 0, GlobalConstant.DATE_PLUS, vo2.getTradeDate().toString());
                String sql3 = "select * from "+table+" " +
                        "where code = '"+code+"' " +
                        "and tradeDate between '"+minVo.getTradeDate()+"' and '"+daysLaterMin+"'" +
                        "and close in (SELECT max(close) FROM "+table+" " +
                        "WHERE code = '"+code+"' " +
                        "and tradeDate between '"+minVo.getTradeDate()+"' and '"+daysLaterMin+"'" +
                        ") " +
                        "order by tradeDate desc " +
                        "limit 1";
                System.out.println("sql3:"+sql3);
                ResultSet rs3 = stmt.executeQuery(sql3);
                while (rs3.next()) {
                    vo3.setTradeDate(rs3.getInt("tradeDate"));
                    vo3.setClose(rs3.getDouble("close"));
                    vo3.setOpen(rs3.getDouble("open"));
                    list.add(vo3);
                }
            }

            //获取交易日相隔的天数add by andrew
//            int days = SpringContextUtil.getBean(TradingDateUtil.class).getDaysBetween(maxVo.getTradeDate().toString(),vo2.getTradeDate().toString());
//            list.add(days);
//            list.add(vo2.getClose()-maxVo.getClose());
        } catch (Exception throwables) {
            throwables.printStackTrace();

        } finally {
            H2ConnectionPool.returnConnection(conn);
        }

        return list;
    }


    /**
     * 获取最大的收盘价
     */
    public static StockPriceDaily getPointOfTop(List<StockPriceDaily> list){
        StockPriceDaily pointOfTop = null;
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);
            if (i == 0) {
                pointOfTop = currentStock;
            } else {
                if (currentStock.getClose() >= pointOfTop.getClose()) {
                    pointOfTop = currentStock;
                }

            }
        }

        return pointOfTop;

    }

    /**
     * 获取最小的收盘价
     */
    public static StockPriceDaily getPointOfBottom(List<StockPriceDaily> list){
        StockPriceDaily pointOfBottom = null;
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);
            if (i == 0) {
                pointOfBottom = currentStock;
            } else {
                if (currentStock.getClose() <= pointOfBottom.getClose()) {
                    pointOfBottom = currentStock;
                }

            }
        }

        return pointOfBottom;
    }

    /**
     * 获取最早的收盘价
     */
    public static StockPriceDaily getPointOfLeft(List<StockPriceDaily> list){
        StockPriceDaily stock = list.get(0);
        return stock;
    }

    /**
     * 获取最新的收盘价
     */
    public static StockPriceDaily getPointOfRight(List<StockPriceDaily> list){
        StockPriceDaily stock = list.get(list.size() - 1);
        return stock;
    }


    /**
     * 获取最大的成交量
     */
    public static StockPriceDaily getPointOfTopVol(List<StockPriceDaily> list){
        StockPriceDaily pointOfTop = null;
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);
            if (i == 0) {
                pointOfTop = currentStock;
            } else {
                if (currentStock.getVol() >= pointOfTop.getVol()) {
                    pointOfTop = currentStock;
                }

            }
        }

        return pointOfTop;

    }


    /**
     * 获取最小的收盘价
     */
    public static StockPriceDaily getPointOfBottomVol(List<StockPriceDaily> list){
        StockPriceDaily pointOfBottom = null;
        for (int i = 0; i < list.size(); i++) {
            StockPriceDaily currentStock = list.get(i);
            if (i == 0) {
                pointOfBottom = currentStock;
            } else {
                if (currentStock.getVol() <= pointOfBottom.getVol()) {
                    pointOfBottom = currentStock;
                }

            }
        }

        return pointOfBottom;
    }

    /**
     * 5,30
     * 32,30
     */
    public static List<StockPriceDaily> getNdaysData(List<StockPriceDaily> list,int n){
        List<StockPriceDaily> newList = new ArrayList<StockPriceDaily>();
        if (list.size()-n<0) {
            return list;
        }

        if (list.size()-n>=0)  {
            for (int i = 0; i < list.size(); i++) {
                if (i>=list.size()-n){
                    newList.add(list.get(i));
                }
            }
            return newList;
        }
        return newList;
    }

    /**
     * 回调进行过滤
     */
    public static List getListByAdjustFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            List<StockPriceDaily> stockPriceDaily = getStockPriceDailyByCode(template, code);
            List<StockPriceDaily> newList = getNdaysData(stockPriceDaily, 30);
            StockPriceDaily pointOfTop = StockUtil.getPointOfTop(newList);
            StockPriceDaily pointOfRight = StockUtil.getPointOfRight(newList);

            double diff = pointOfTop.getClose()- pointOfRight.getClose();
            double result = diff*100/ pointOfTop.getClose();

            if (begin != null && end != null) {
                if (result>= begin && result<end) {
                    //符合条件
                } else {
                    removeList.add(stock);
                }

            }
        }
        list.removeAll(removeList);
        return list;
    }

    /**近期缩量倍数进行过滤
     * 放量缩量比率,倍数越大，缩量越明显
     */
    public static List getListByVolReducedRatioFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            List<StockPriceDaily> stockPriceDaily = getStockPriceDailyByCode(template, code);
            List<StockPriceDaily> newList = getNdaysData(stockPriceDaily, 30);
            StockPriceDaily pointOfTopVol = StockUtil.getPointOfTopVol(newList);
            StockPriceDaily pointOfRight = StockUtil.getPointOfRight(newList);

            double result = pointOfTopVol.getVol()/pointOfRight.getVol();


            if (begin != null && end != null) {
                if (result>= begin && result<end) {
                    //符合条件
                    log.info("========符合条件，{}-{}近30天缩量：{}",stock.getCode(),stock.getName(),result);
                } else {
                    removeList.add(stock);
                    log.info("{}-{}近30天缩量：{}",stock.getCode(),stock.getName(),result);
                }

            }
        }
        list.removeAll(removeList);
        return list;
    }
    /**
     * x天内出现地量进行过滤
     */
    public static List getListByLowestVolFilter(MongoTemplate template,List<Stock> list,String lowestVolFilter)  {
        ArrayList<Stock> removeList = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            List<StockPriceDaily> stockPriceDaily = getStockPriceDailyByCode(template, code);
            List<StockPriceDaily> newList = getNdaysData(stockPriceDaily, Integer.valueOf(lowestVolFilter).intValue());
            StockPriceDaily pointOfBottomVolOfFilter = getPointOfBottomVol(newList);
            StockPriceDaily pointOfBottomVolOfYear = getPointOfBottomVol(stockPriceDaily);

            if (pointOfBottomVolOfYear.getVol().equals(pointOfBottomVolOfFilter.getVol())){
                //符合条件
            } else {
                removeList.add(stock);
            }

        }
        list.removeAll(removeList);
        return list;
    }

    /**
     * 总市值（亿）进行过滤
     */
    public static List getListByTotalMarketValueFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            Double totalValue = stock.getTotalValue();

            double result = totalValue.doubleValue();
            if (begin != null && end != null) {
                if (result>= begin && result<end) {
                    //符合条件
                } else {
                    removeList.add(stock);
                }

            }
        }
        list.removeAll(removeList);
        return list;
    }
    /**
     * 过滤掉创业板、科创板、st、*st股票
     */
    public static List getListByTypeFilter(List<Stock> list, MongoTemplate template) {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            String stockName = stock.getName();

            if (code.startsWith(GlobalConstant.INDEX_CYB_PREFIX)||code.startsWith(GlobalConstant.INDEX_KYB_PREFIX)){
                removeList.add(stock);
            }

            if (stockName.startsWith(GlobalConstant.INDEX_ST_NAME_PREFIX)||stockName.startsWith(GlobalConstant.INDEX_ST_NAME_START_PREFIX)){
                removeList.add(stock);
            }

        }
        list.removeAll(removeList);
        return list;
    }

    /**
     * 根据价格进行过滤掉
     */
    public static List getListByPriceFilter(MongoTemplate template,List<Stock> list,Double begin,Double end) {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            List<StockPriceDaily> stockPriceDaily = getStockPriceDailyByCode(template, code);
            StockPriceDaily currentStockPrice = StockUtil.getPointOfRight(stockPriceDaily);
            double close = currentStockPrice.getClose();
            if (begin != null && end != null) {
                if (close>= begin && close<end) {
                    //符合条件
                } else {
                    removeList.add(stock);
                }
            }

        }
        list.removeAll(removeList);
        return list;
    }

    /**
     * 根据盈亏比进行过滤
     * 0:盈亏比
     * 1:盈
     * 2:亏
     */
    private static List getListByMaybeBase(MongoTemplate template,List<Stock> list,Double begin,Double end,int flag)  {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            List<StockPriceDaily> stockPriceDaily = getStockPriceDailyByCode(template, code);
            List<Double> maybeProfitLoss = StockUtil.getMaybeProfitLoss(stockPriceDaily);
            Double result = 0d;
            if (flag == 0) {
                result = maybeProfitLoss.get(0);
            } else if (flag == 1) {
                result = maybeProfitLoss.get(1);
            } else {
                result = maybeProfitLoss.get(2);
            }

            if (begin != null && end != null) {
                if (result>= begin && result<end) {
                    //符合条件
                } else {
                    removeList.add(stock);
                }

            }
        }
        list.removeAll(removeList);
        return list;
    }
    /**
     * 根据盈亏比进行过滤掉
     */
    public static List getListByMaybeProfitLossFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        return getListByMaybeBase(template,list,begin,end,0);
    }

    /**
     * 根据盈亏比进行过滤掉
     */
    public static List getListByMaybeProfitFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        return getListByMaybeBase(template,list,begin,end,1);
    }
    /**
     * 根据盈亏比进行过滤掉
     */
    public static List getListByMaybeLossFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        return getListByMaybeBase(template,list,begin,end,2);
    }

    /**
     * 根据涨跌幅进行过滤掉
     */
    public static List getListByPctchgFilter(MongoTemplate template,List<Stock> list,Double begin,Double end)  {
        ArrayList<Stock> removeList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            Stock stock = list.get(i);
            String code = stock.getCode();
            List<StockPriceDaily> stockPriceDaily = getStockPriceDailyByCode(template, code);
            StockPriceDaily currentStockPrice = StockUtil.getPointOfRight(stockPriceDaily);
            double result = currentStockPrice.getPctchg();
            if (begin != null && end != null) {
                if (result>= begin && result<end) {
                    //符合条件
                } else {
                    removeList.add(stock);
                }
            }
        }
        list.removeAll(removeList);
        return list;
    }


    public static String getShapeOfCurrent(List<StockPriceDaily> list)  {
        int n = list.size();
        boolean shapeOfHammer = getShapeOfHammer(list.get(n-1));
        boolean shapeOfHangOneself = getShapeOfHangOneself(list.get(n - 1));
        boolean shapeOfStabUp = getShapeOfStabUp(list.get(n - 2), list.get(n - 1));
        boolean shapeOfStabDown = getShapeOfStabDown(list.get(n - 2), list.get(n - 1));
        boolean shapeOfSwallowUp = getShapeOfSwallowUp(list.get(n - 2), list.get(n - 1));
        boolean shapeOfSwallowDown = getShapeOfSwallowDown(list.get(n - 2), list.get(n - 1));
        if (shapeOfHammer) return GlobalEnums.getNameByCode("shapeOfHammer");
        if (shapeOfHangOneself) return GlobalEnums.getNameByCode("shapeOfHangOneself");
        if (shapeOfStabUp) return GlobalEnums.getNameByCode("shapeOfStabUp");
        if (shapeOfStabDown) return GlobalEnums.getNameByCode("shapeOfStabDown");
        if (shapeOfSwallowUp) return GlobalEnums.getNameByCode("shapeOfSwallowUp");
        if (shapeOfSwallowDown) return GlobalEnums.getNameByCode("shapeOfSwallowDown");

        return "无特殊形态";
    }

    /**
     * 锤子线形态
     */
    public static boolean getShapeOfHammer(StockPriceDaily stock){
        boolean isShapeOfHammer = false;
        double val = 0d;
        //锤子形态：阴线
        if (stock.getOpen()>stock.getClose()) {
            val = (stock.getLow()-stock.getClose())/(stock.getClose()-stock.getOpen());
        }

        //锤子形态：阳线
        if (stock.getClose()>stock.getOpen()) {
            val = (stock.getOpen()-stock.getLow())/(stock.getOpen()-stock.getClose());
        }

        if (val>GlobalConstant.isShapeOfHammer) {
            isShapeOfHammer = true;
        } else {
            isShapeOfHammer = false;
        }
        return isShapeOfHammer;
    }

    /**
     * 上吊线形态
     */
    public static boolean getShapeOfHangOneself(StockPriceDaily stock){
        boolean isShapeOfHangOneself = false;
        double val = 0d;
        //阴线
        if (stock.getOpen()>stock.getClose()) {
            val = (stock.getHigh()-stock.getOpen())/(stock.getOpen()-stock.getClose());
        }

        //阳线
        if (stock.getClose()>stock.getOpen()) {
            val = (stock.getHigh()-stock.getClose())/(stock.getClose()-stock.getOpen());
        }

        if (val>GlobalConstant.isShapeOfHangOneself) {
            isShapeOfHangOneself = true;
        } else {
            isShapeOfHangOneself = false;
        }
        return isShapeOfHangOneself;
    }

    /**
     * 上涨吞没形态
     */
    public static boolean getShapeOfSwallowUp(StockPriceDaily stock1,StockPriceDaily stock2) {
        if (stock2.getClose() > stock1.getClose() && stock2.getOpen() < stock1.getClose()) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 下跌吞没形态
     */
    public static boolean getShapeOfSwallowDown(StockPriceDaily stock1,StockPriceDaily stock2) {
        if (stock2.getOpen() > stock1.getClose() && stock2.getClose() < stock1.getOpen()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 刺透：向上
     */
    public static boolean getShapeOfStabUp(StockPriceDaily stock1,StockPriceDaily stock2) {
        if (stock2.getClose() > stock1.getOpen() && stock2.getClose() > (stock1.getOpen() - stock1.getClose())/2 + stock1.getClose() && stock1.getClose() > stock2.getOpen()) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 刺透：向下（乌云盖顶）
     */
    public static boolean getShapeOfStabDown(StockPriceDaily stock1,StockPriceDaily stock2) {
        if (stock2.getOpen() > stock1.getClose() && stock2.getClose() > stock1.getOpen() && stock2.getClose() < stock1.getOpen() + (stock1.getClose() - stock1.getOpen())/2) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 可能的盈利空间
     * @param list
     * @return
     */
    public static double getMaybeProfit(List<StockPriceDaily> list){
        StockPriceDaily pointOfTop = getPointOfTop(list);
        StockPriceDaily pointOfRight = getPointOfRight(list);
        double diff = pointOfTop.getClose()- pointOfRight.getClose();
        double maybeProfit = diff*100/pointOfRight.getClose();
        return maybeProfit;
    }

    /**
     * 可能的亏损空间
     * @param list
     * @return
     */
    public static double getMaybeLoss(List<StockPriceDaily> list){
        StockPriceDaily pointOfBottom = getPointOfBottom(list);
        StockPriceDaily pointOfRight = getPointOfRight(list);
        double diff = pointOfRight.getClose()- pointOfBottom.getClose();
        double maybeLoss = diff*100/pointOfRight.getClose();
        return maybeLoss;
    }

    /**
     * 可能的盈亏比
     * @param list
     * @return
     */
    public static List<Double> getMaybeProfitLoss(List<StockPriceDaily> list){
        double maybeProfit = getMaybeProfit(list);
        double maybeLoss = getMaybeLoss(list);
        double maybeProfitLoss = maybeProfit/maybeLoss;
        return Arrays.asList(maybeProfitLoss,maybeProfit,maybeLoss);
    }

    /**
     * 获取趋势
     */
    public static void getTrend(){

    }

    /**
     * https://blog.csdn.net/weixin_39538847/article/details/111907800
     * @param nums
     * @return
     */
    public static int getWavePeak(Integer[] nums) {
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        while(left < right){
            mid = left + (right - left)/2;
            if(mid == 0 && nums[mid] > nums[mid+1] ||
                    mid == nums.length - 1 && nums[mid] > nums[mid-1] ||
                    nums[mid] > nums[mid+1] && nums[mid] > nums[mid-1]){
                return mid;
            }

            if(nums[mid] > nums[mid+1]){ // 左边肯定有峰值
                right = mid;
            }else{
                left = mid + 1;

            }
        }

        return left;
    }

    /**
     * https://blog.csdn.net/jjwwwww/article/details/82802436
     * @param data
     * @return
     */
    public static int getPeakNum1(Double[] data){
        int peak=0;

        for (int i=0;i<data.length-1;i++){
            if (data[i]>data[i-1]&&data[i]>data[i+1]){
                peak++;
                i++;
            }
        }

        return peak;
    }

    public static int getPeakNum2(Double[] data){
        int peak=0;

        //需要三个不同的值进行比较，取lo,mid，hi分别为三值
        for (int lo=0,mid=1,hi=2;hi<data.length;hi++){
            //先令data[lo]不等于data[mid]
            while (mid<data.length&&data[mid]==data[lo]){
                mid++;
            }

            hi=mid+1;

            //令data[hi]不等于data[mid]
            while (hi<data.length&&data[hi]==data[mid]){
                hi++;
            }

            if (hi>=data.length){
                break;
            }

            //检测是否为峰值
            if (data[mid]>data[lo]&&data[mid]>data[hi]){
                peak++;
            }

            lo=mid;
            mid=hi;
        }

        return peak;
    }

    /**
     * 判断当前股票代码是否为指数
     * @param code
     * @return
     */
    public static boolean isIndexes(String code){
        if (code.equals(GlobalConstant.INDEX_SH)){
            return true;
        }
        if (code.equals(GlobalConstant.INDEX_SZ)){
            return true;
        }
        if (code.equals(GlobalConstant.INDEX_CYB)){
            return true;
        }
        if (code.equals(GlobalConstant.INDEX_KCB)){
            return true;
        }
        return false;
    }

    public static int getPeakNum3(Double[] data){
        int peak=0;

        float[] PeakAndTrough=new float[data.length];

        //需要三个不同的值进行比较，取lo,mid，hi分别为三值
        for (int lo=0,mid=1,hi=2;hi<data.length;hi++){
            //先令data[lo]不等于data[mid]
            while (mid<data.length&&data[mid]==data[lo]){
                mid++;
            }

            hi=mid+1;

            //令data[hi]不等于data[mid]
            while (hi<data.length&&data[hi]==data[mid]){
                hi++;
            }

            if (hi>=data.length){
                break;
            }

            //检测是否为峰值
            if (data[mid]>data[lo]&&data[mid]>data[hi]){
                PeakAndTrough[mid]=1;       //1代表波峰
            }else if(data[mid]<data[lo]&&data[mid]<data[hi]){
                PeakAndTrough[mid]=-1;      //-1代表波谷
            }

            lo=mid;
            mid=hi;
        }

        //计算均值
        float ave=0;
        for (int i=0;i<data.length;i++){
            ave+=data[i];
        }
        ave/=data.length;

        //排除大于均值的波谷和小于均值的波峰
        for (int i=0;i<PeakAndTrough.length;i++){
            if ((PeakAndTrough[i]>0&&data[i]<ave)||(PeakAndTrough[i]<0&&data[i]>ave)){
                PeakAndTrough[i]=0;
            }
        }

        //统计波峰数量
        for (int i=0;i<PeakAndTrough.length;){
            while (i<PeakAndTrough.length&&PeakAndTrough[i]<=0){
                i++;
            }

            if (i>=PeakAndTrough.length){
                break;
            }

            peak++;

            while (i<PeakAndTrough.length&&PeakAndTrough[i]>=0){
                i++;
            }
        }

        return peak;
    }

    public static void main(String[] args) {
//        List<Integer> list = Arrays.asList(1, 2, 1, 3, 5, 6, 4);
//        Integer[] arr = (Integer[])list.toArray();
//        System.out.println(getWavePeak(arr));


        List<Double> listf = Arrays.asList(1.2, 2.0, 1.5, 3.2, 5.1, 6.7, 4.8);
        Double[] arrf = (Double[])listf.toArray();
        System.out.println(getPeakNum2(arrf));



    }
}
